//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 6/25/2008 11:27:09 AM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using System.Drawing;
using Microsoft.DirectX.Direct3D;
using MapWindow.Drawing;
using MapWindow.Geometries;

namespace MapWindow.DirectX
{


    /// <summary>
    /// TexturedWedgeList
    /// </summary>
    public class TexturedWedgeListDX : PrimitiveBaseDX
    {
        #region Private Variables

        readonly float _width;
        ILineSymbolizer _symbolizer;
   

        #endregion

        #region Constructors

      

        /// <summary>
        /// Creates a new instance of TexturedWedgeList, and specifies the symbolizer to use
        /// </summary>
        /// <param name="inSymbolizer">A Line Symbolizer to generate a texture from</param>
        public TexturedWedgeListDX(ILineSymbolizer inSymbolizer)
        {
            _width = (float)inSymbolizer.GetWidth();
            _symbolizer = inSymbolizer;
        }

        #endregion

        #region Methods


       

        /// <summary>
        /// Adds a Wedge to the list of wedges.  This will be calculated by looking at the segments.
        /// </summary>
        /// <param name="start">The start point for the segment before the wedge</param>
        /// <param name="center">The center point where the wedge will be inserted</param>
        /// <param name="end">The end point for the segment after the wedge</param>
        public void AddWedge(Coordinate start, Coordinate center, Coordinate end)
        {


            double mZ = center.Z;
            if (double.IsNaN(mZ)) mZ = 0.0;
            double sZ = start.Z;
            if (double.IsNaN(sZ)) sZ = 0.0;
            double eZ = end.Z;
            if (double.IsNaN(eZ)) eZ = 0.0;
            float tu;


            Vector vCenter = new Vector(center.X, center.Y, mZ);
            Vector vStart = new Vector(start.X, start.Y, sZ);
            Vector vEnd = new Vector(end.X, end.Y, eZ);

            Vector leftStart = Perpendicular(vStart, vCenter);
            Vector leftEnd = Perpendicular(vCenter, vEnd);
            Vector dirStart = vCenter.Subtract(vStart);

            PositionTexturedVC verts = Vertices as PositionTexturedVC;
            if (verts == null)
            {
                throw new InvalidOperationException(
                    "The underlying vertex collection was not the correct type to support textures.");
            }

            verts.AddCoordinate(vCenter, .5f, .5f);

            if (leftEnd.Dot(dirStart) < 0)
            {
                // The left side of this joint is squashed, so create the wedge from the other side
                leftStart = leftStart.Multiply(_width/2);
                Vector vWedge2 = vCenter.Subtract(leftStart);
                tu = .5F - Convert.ToSingle(Math.Abs(leftStart.X));
                    // This ensures the border width is correct and that the texture isn't scaled down to the size of the wedge.
                verts.AddCoordinate(vWedge2, tu, 1);

                leftEnd = leftEnd.Multiply(_width/2);
                Vector vWedge3 = vCenter.Subtract(leftEnd);
                tu = .5F + Convert.ToSingle(Math.Abs(leftEnd.X));
                verts.AddCoordinate(vWedge3, tu, 1);
            }
            else
            {
                leftStart = leftStart.Multiply(_width/2);
                Vector vWedge2 = vCenter.Add(leftStart);
                tu = .5f - Convert.ToSingle(Math.Abs(leftStart.X));
                    // This ensures the border width is correct and that the texture isn't scaled down to the size of the wedge.
                verts.AddCoordinate(vWedge2, tu, 0);

                leftEnd = leftEnd.Multiply(_width/2);
                Vector vWedge3 = vCenter.Add(leftEnd);
                tu = .5f + Convert.ToSingle(Math.Abs(leftEnd.X));
                verts.AddCoordinate(vWedge3, tu, 0);
            }
        }



        private static Vector Perpendicular(Vector start, Vector end)
        {
            Vector up = new Vector(0, 0, 1);
            Vector dir = end.Subtract(start);
            Vector perp = up.Cross(dir);
            perp.Normalize();
            return perp;
        }

        /// <summary>
        /// Occurs as the Wedge List is being initialized (or reset).  This will force the creation
        /// of a new texture for the wedges.
        /// </summary>
        /// <param name="e">A DrawArgsDX event argument</param>
        protected override void OnInitialize(DrawArgsDX e)
        {
            int w = (int) _symbolizer.GetWidth();
            Bitmap bmp = new Bitmap(w, w);
            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            _symbolizer.Draw(g, new Rectangle(0, 0, bmp.Width-1, bmp.Height-1));
            g.Dispose();
            TextureComp.TextureDX = new Texture(e.Device, bmp, Usage.AutoGenerateMipMap, Pool.Managed);
 	        
            base.OnInitialize(e);
        }

       

      


      


        #endregion

        #region Properties

       

        /// <summary>
        /// Gets or sets the symbolizer to use
        /// </summary>
        public ILineSymbolizer Symbolizer
        {
            get { return _symbolizer; }
            set { _symbolizer = value; }
        }

       
        #endregion



    }
}
